package com.itisyue.fun.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.*;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

public class HttpUtil {
    private static Logger log = LoggerFactory.getLogger(HttpUtil.class);

    private static final ContentType STRING_CONTENT_TYPE = ContentType.create("text/plain", StandardCharsets.UTF_8);

    /**
     * post请求接口
     * @param url
     * @param file
     * @param formParams
     * @return
     */
    public static String postResultMultipartFile(String url,  MultipartFile file, Map<String, String> formParams) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        String result = "";
        HttpEntity httpEntity = null;
        HttpEntity responseEntity = null;
        try {
            String fileName = file.getOriginalFilename();
            HttpPost httpPost = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().
                    setConnectTimeout(180 * 1000).setConnectionRequestTimeout(180 * 1000)
                    .setSocketTimeout(180 * 1000).setRedirectsEnabled(true).build();
            httpPost.setConfig(requestConfig);
            //添加header
//            for (Map.Entry<String, String> e : headerParams.entrySet()) {
//                httpPost.addHeader(e.getKey(), e.getValue());
//            }
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.setCharset(Charset.forName("utf-8"));
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//加上此行代码解决返回中文乱码问题
            builder.addBinaryBody("file", file.getInputStream(), ContentType.MULTIPART_FORM_DATA, fileName);// 文件流
//            builder.addBinaryBody("file", file.getInputStream(), ContentType.APPLICATION_OCTET_STREAM, fileName);// 文件流
            for (Map.Entry<String, String> e : formParams.entrySet()) {
                builder.addTextBody(e.getKey(), e.getValue());// 类似浏览器表单提交，对应input的name和value
            }
            httpEntity = builder.build();
            httpPost.setEntity(httpEntity);
            HttpResponse response = httpClient.execute(httpPost);// 执行提交
            responseEntity = response.getEntity();
            if (responseEntity != null) {
                // 将响应内容转换为字符串
                result = EntityUtils.toString(responseEntity, Charset.forName("UTF-8"));
            }
        } catch (IOException e) {
            log.error("------------------{}",e.getMessage());
            e.printStackTrace();
        }catch (Exception e) {
            log.error("------------------{}",e.getMessage());
            e.printStackTrace();
        }  finally {
            log.info(url, HttpMethod.POST, httpEntity, null, responseEntity);
        }
        return result;
    }

    public static String multipartPost(String url, Map<String, String> headers, Map<String, Object> paramMap) {
        // 创建 HttpPost 对象
        HttpPost httpPost = new HttpPost(url);
        // 设置请求头
        if (MapUtils.isNotEmpty(headers)) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                httpPost.setHeader(key, value);
            }
        }
        // 设置请求参数
        if (MapUtils.isNotEmpty(paramMap)) {
            // 使用 MultipartEntityBuilder 构造请求体
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            //设置浏览器兼容模式
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            //设置请求的编码格式
            builder.setCharset(Consts.UTF_8);
            // 设置 Content-Type
            builder.setContentType(ContentType.MULTIPART_FORM_DATA);
            for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                String key = entry.getKey();
                Object value = paramMap.get(key);
                // 添加请求参数
                addMultipartBody(builder, key, value);
            }
            HttpEntity entity = builder.build();
            // 将构造好的 entity 设置到 HttpPost 对象中
            httpPost.setEntity(entity);
        }
        return execute(httpPost, null);
    }

    private static String execute(HttpRequestBase httpRequestBase, HttpContext context) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 使用 try-with-resources 发起请求，保证请求完成后资源关闭
        try (CloseableHttpResponse httpResponse = httpClient.execute(httpRequestBase, context)) {
            // 处理响应头
            Map<String, List<String>> headers = headerToMap(httpResponse.getAllHeaders());
            // 处理响应体
            HttpEntity httpEntity = httpResponse.getEntity();
            if (httpEntity != null) {
                String entityContent = EntityUtils.toString(httpEntity, Consts.UTF_8);
                return entityContent;
                //return new FacadeResponse(httpRequestBase.getRequestLine().getUri(), httpResponse.getStatusLine().getStatusCode(), headers, entityContent);
            }
        } catch (Exception ex) {
            log.error("http execute failed.", ex);
        }
        return "";
//        return new FacadeResponse(httpRequestBase.getRequestLine().getUri(), HttpStatus.INTERNAL_SERVER_ERROR.value(), null, "http execute failed.");
    }

    private static void addMultipartBody(MultipartEntityBuilder builder, String key, Object value) {
        if (value == null) {
            return;
        }
        // MultipartFile 是 spring mvc 接收到的文件。
        if (value instanceof MultipartFile) {
            MultipartFile file = (MultipartFile) value;
            try {
                builder.addBinaryBody(key, file.getInputStream(), ContentType.MULTIPART_FORM_DATA, file.getOriginalFilename());
            } catch (IOException e) {
                log.error("read file err.", e);
            }
        } else if (value instanceof File) {
            File file = (File) value;
            builder.addBinaryBody(key, file, ContentType.MULTIPART_FORM_DATA, file.getName());
        } else if (value instanceof List) {
            // 列表形式的参数，要一个一个 add
            List<?> list = (List<?>) value;
            for (Object o : list) {
                addMultipartBody(builder, key, o);
            }
        } else if (value instanceof Date) {
            // 日期格式的参数，使用约定的格式
            builder.addTextBody(key, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value));
        } else {
            // 使用 UTF_8 编码的 ContentType，否则可能会有中文乱码问题
            builder.addTextBody(key, value.toString(), STRING_CONTENT_TYPE);
        }
    }

    /**
     * 将headers转map
     *
     * @param headers 头信息
     * @return map
     */
    private static Map<String, List<String>> headerToMap(Header[] headers) {
        if (null == headers || headers.length == 0) {
            return Collections.emptyMap();
        }
        Map<String, List<String>> map = new HashMap<>();
        for (Header header : headers) {
            List<String> list = Arrays.asList(header.getValue());
            map.putIfAbsent(header.getName(), list);
        }
        return map;
    }

    /**
     * post请求以及参数是json
     *
     * @param url
     * @param jsonParams
     * @return
     */
    public static JSONObject doPostForJson(String url, String jsonParams) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        JSONObject jsonObject = null;
        HttpPost httpPost = new HttpPost(url);
        RequestConfig requestConfig = RequestConfig.custom().
                setConnectTimeout(180 * 1000).setConnectionRequestTimeout(180 * 1000)
                .setSocketTimeout(180 * 1000).setRedirectsEnabled(true).build();
        httpPost.setConfig(requestConfig);
        httpPost.setHeader("Content-Type", "application/json");
        try {
            httpPost.setEntity(new StringEntity(jsonParams, ContentType.create("application/json", "utf-8")));
            //log.info("request parameters" + EntityUtils.toString(httpPost.getEntity()));
            //log.info("httpPost:" + httpPost);
            HttpResponse response = httpClient.execute(httpPost);
            if (response != null && response.getStatusLine().getStatusCode() == 200) {
                String result = EntityUtils.toString(response.getEntity());
                //log.info("result:" + result);
                jsonObject = JSON.parseObject(result);
                return jsonObject;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return jsonObject;
        }
    }

    public static JSONObject doGet(String url, Map<String, Object> mapParams, Map<String, String> mapHeader) {
        StringBuffer sb = new StringBuffer();//map参数格式化成url发送参数格式
        String params = "";//格式化之后url传递的参数
        try {
            if(mapParams!=null){
                // 格式化参数
                if (mapParams.size() == 1) {
                    for (Map.Entry<String, Object> entry : mapParams.entrySet()) {
                        sb.append(entry.getKey()).append("=").append(
                                entry.getValue() == null ? null : java.net.URLEncoder.encode(entry.getValue().toString(), "UTF-8"));  //对参数进行编码格式化以及拼接
                    }
                    params = sb.toString();
                } else {
                    for (Map.Entry<String, Object> entry : mapParams.entrySet()) {
                        sb.append(entry.getKey()).append("=").append(
                                entry.getValue() == null ? null : java.net.URLEncoder.encode(entry.getValue().toString(), "UTF-8")).append("&");  //对参数进行编码格式化以及拼接
                    }
                    params = sb.toString().substring(0, sb.toString().length() - 1);
                }
                url = url + "?" + params;  //拼接url和参数
            }
        }catch (Exception e){
        }

        CloseableHttpClient httpClient = HttpClients.createDefault();
        JSONObject jsonObject = null;
        System.out.println(url);
        HttpGet httpGet = new HttpGet(url);
        RequestConfig requestConfig = RequestConfig.custom().
                setConnectTimeout(180 * 1000).setConnectionRequestTimeout(180 * 1000)
                .setSocketTimeout(180 * 1000).setRedirectsEnabled(true).build();
        httpGet.setConfig(requestConfig);
        httpGet.setHeader("Content-Type", "application/json");
        if(mapHeader!=null){
            Set<String> headerKeySet = mapHeader.keySet();
            for(String headerKey: headerKeySet){
                String headerVal = mapHeader.get(headerKey);
                httpGet.setHeader(headerKey, headerVal);
            }
        }
        try {
            //log.info("request parameters" + EntityUtils.toString(httpPost.getEntity()));
            //log.info("httpPost:" + httpPost);
            HttpResponse response = httpClient.execute(httpGet);
            if (response != null && response.getStatusLine().getStatusCode() == 200) {
                String result = EntityUtils.toString(response.getEntity());
                //log.info("result:" + result);
                jsonObject = JSON.parseObject(result);
                return jsonObject;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return jsonObject;
        }
    }


    /**
     * ContentType.URLENCODED.getHeader()
     * @param map
     * @param url
     * @param headerMap
     * @param contentType
     * @return
     * @throws Exception
     */
    public static String post(String url, Map<String, String> map, Map<String, String> headerMap, String contentType) throws Exception{
        CloseableHttpClient httpclient = HttpClientBuilder.create().build();
        HttpPost post = new HttpPost(url);
        CloseableHttpResponse response = null;
        InputStream in = null;
        BufferedReader br = null;
        String result = "";
        try {
            List<NameValuePair> nameValuePairs = getNameValuePairList(map);
            UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(nameValuePairs, "UTF-8");
            /*发送json数据需要设置contentType*/
            urlEncodedFormEntity.setContentType(contentType);
            post.setEntity(urlEncodedFormEntity);
            post.setHeader("Content-Type", contentType);
            Set<Map.Entry<String, String>> headerEntries = headerMap.entrySet();
            for (Map.Entry<String, String> headerEntry:headerEntries){
                post.setHeader(headerEntry.getKey(), headerEntry.getValue());
            }
            response = httpclient.execute(post);
            in = response.getEntity().getContent();
            br = new BufferedReader(new InputStreamReader(in, "utf-8"));
            StringBuilder strber= new StringBuilder();
            String line = null;
            while((line = br.readLine())!=null){
                strber.append(line+'\n');
            }
            result = strber.toString();
            if(response.getStatusLine().getStatusCode()!= HttpStatus.SC_OK){
                if(StringUtils.isBlank(result)) result = "服务器异常";
                throw new Exception(result);
            }
            //System.out.println("返回数据="+result);
        } catch (Exception e) {
            //System.err.println("调用接口出错：：：：：：：：：：：："+e.getMessage());
            throw new Exception(e.getMessage());
        } finally {
            br.close();
            in.close();
            response.close();
            httpclient.close();
        }
        return result;
    }
    private static List<NameValuePair> getNameValuePairList(Map<String, String> map) {
        List<NameValuePair> list = new ArrayList<>();
        for(String key : map.keySet()) {
            list.add(new BasicNameValuePair(key,map.get(key)));
        }

        return list;
    }
    public static void downloadByUrl1(String urlPath, String filePath, Map<String, String> headerMap) throws IOException {

        try {
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            HttpGet httpGet = new HttpGet(urlPath);
            if(headerMap!=null){
                Set<String> headerKeySet = headerMap.keySet();
                for(String headerKey: headerKeySet){
                    String headerVal = headerMap.get(headerKey);
                    httpGet.setHeader(headerKey, headerVal);
                }
            }
            CloseableHttpResponse response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();

            String newUrl = "";
            if(statusCode == 302){
                Header header = response.getFirstHeader("location");
                newUrl = header.getValue();
                log.info("statusCode={}, newUrl={}", statusCode, newUrl);

                httpGet = new HttpGet(newUrl);
                if(headerMap!=null){
                    Set<String> headerKeySet = headerMap.keySet();
                    for(String headerKey: headerKeySet){
                        String headerVal = headerMap.get(headerKey);
                        httpGet.setHeader(headerKey, headerVal);
                    }
                }
                response = httpClient.execute(httpGet);
            }


            if (response.getStatusLine().getStatusCode() == 200) {
                // 得到实体
                HttpEntity entity = response.getEntity();
                InputStream inputStream = entity.getContent();
                byte[] getData = readInputStream(inputStream);
                File file = new File(filePath);
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(getData);
                fos.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void downloadByUrl(String urlPath, String filePath, Map<String, String> headerMap) throws IOException {
        try {
            URL url = new URL(urlPath);
            HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
            httpConn.setRequestMethod("GET");
            httpConn.setInstanceFollowRedirects(false);

            if(headerMap!=null){
                Set<String> headerKeySet = headerMap.keySet();
                for(String headerKey: headerKeySet){
                    String headerVal = headerMap.get(headerKey);
                    httpConn.setRequestProperty(headerKey, headerVal);
                }
            }
            httpConn.connect();
            int statusCode = httpConn.getResponseCode();
            if(statusCode==302){
                String newUri = httpConn.getHeaderField("location");
//                String newUri = httpConn.getURL().toString();
                URL newUrl = new URL(newUri);
                httpConn = (HttpURLConnection) newUrl.openConnection();
                httpConn.setRequestMethod("GET");
                statusCode = httpConn.getResponseCode();
            }
            if(statusCode==200){
                InputStream inputStream = httpConn.getInputStream();
                byte[] getData = readInputStream(inputStream);
                File file = new File(filePath);
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(getData);
                fos.close();
                inputStream.close();
            }



//            BufferedWriter bufferwriter = new BufferedWriter(new FileWriter(filePath));
//
//            BufferedReader in = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));
//            String inputLine;
//            StringBuffer response = new StringBuffer();
//            while ((inputLine = in.readLine()) != null) {
//                response.append(inputLine);
//                bufferwriter.write(inputLine);
//            }
//            String s = response.toString();
//            log.info("file str size:{}", s.getBytes().length);
//            bufferwriter.flush();
//            bufferwriter.close();
//            in.close();

//            System.out.println(response.toString());
        } catch (Exception e) {
            log.error("下载出错: ",e);
        }
    }
    public static  byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }

    public static void main(String[] args) {
//        JSONObject jsonObject = doGet("http://127.0.0.1:801/test01", null,null);
//        System.out.println(jsonObject.toJSONString());


        JSONObject jsonObject = doGet("http://127.0.0.1:801/baiduDiskAccessTokenCallBack/#expires_in=2592000&access_token=123.533e93ef43fb85086a5a7620ace01c7e.YB7s__DZ2L5ki-vBgK3DswEGByxMhsInuHshOU-.d5aOIA&session_secret=&session_key=&scope=basic+netdisk", null,null);
        System.out.println(jsonObject.toJSONString());
    }
}
